package cn.iocoder.yudao.module.pay.wechat.mq;

import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.module.api.infrastructure.wechat.WechatClientApi;
import cn.iocoder.yudao.module.api.infrastructure.wechat.dto.WxaOrderNotifyConfirmReceiveDTO;
import cn.iocoder.yudao.module.api.infrastructure.wechat.dto.WxaUploadOrderShippingInfoDTO;
import cn.iocoder.yudao.module.api.infrastructure.wechat.vo.WechatOrderDetailVO;
import cn.iocoder.yudao.module.api.member.agency.message.AgencyOrderPaidMessage;
import cn.iocoder.yudao.module.api.member.agency.vo.AgencyOrderVO;
import cn.iocoder.yudao.module.api.member.alliance.message.CloudAllianceOrderPaidMessage;
import cn.iocoder.yudao.module.api.member.alliance.vo.CloudAllianceOrderVO;
import cn.iocoder.yudao.module.api.member.vip.message.VipOrderPaidMessage;
import cn.iocoder.yudao.module.api.member.vip.vo.VipOrderVO;
import cn.iocoder.yudao.module.api.pay.order.PayOrderApi;
import cn.iocoder.yudao.module.api.pay.order.eums.UnifiedPayChannelEnum;
import cn.iocoder.yudao.module.api.pay.order.vo.PayOrderVO;
import cn.iocoder.yudao.module.api.pay.wallet.message.WalletRechargerPaidMessage;
import cn.iocoder.yudao.module.api.pay.wechat.message.WechatOrderInfoSyncMessage;
import cn.iocoder.yudao.module.api.pay.wechat.message.WechatOrderShippingMessage;
import cn.iocoder.yudao.module.api.trade.delivery.enums.DeliveryTypeEnum;
import cn.iocoder.yudao.module.api.trade.order.dto.TradeOrderRespDTO;
import cn.iocoder.yudao.module.api.trade.order.message.TradeOrderCompletedMessage;
import cn.iocoder.yudao.module.api.trade.order.message.TradeOrderDeliveryMessage;
import cn.iocoder.yudao.module.api.trade.scan.dto.ScanOrderDTO;
import cn.iocoder.yudao.module.api.trade.scan.message.ScanOrderPaidMessage;
import cn.iocoder.yudao.module.pay.wechat.dao.WechatOrderInfoMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

/**
 * 微信发货信息 事件消费者
 *
 * @author 山野羡民
 */
@Component
@Slf4j
public class WechatOrderConsumer {

    @EventListener
    @Async // Spring Event 默认在 Producer 发送的线程，通过 @Async 实现异步
    public void onMessage(TradeOrderDeliveryMessage message) {
        TradeOrderRespDTO order = message.getOrder();
        log.info("[pay/wechat][onMessage][交易订单发货事件({}/{})]", order.getNo(), order.getPayNo());
        tryUploadWxMaOrderShippingInfo(order);
    }

    @EventListener
    @Async // Spring Event 默认在 Producer 发送的线程，通过 @Async 实现异步
    public void onMessage(TradeOrderCompletedMessage message) {
        TradeOrderRespDTO order = message.getOrder();
        log.info("[pay/wechat][onMessage][交易订单完成事件({}/{})]", order.getNo(), order.getPayNo());
        tryNotifyWxMaOrderConfirmReceive(order);
    }

    @EventListener
    @Async // Spring Event 默认在 Producer 发送的线程，通过 @Async 实现异步
    public void onMessage(ScanOrderPaidMessage message) {
        ScanOrderDTO order = message.getOrder();
        log.info("[pay/wechat][onMessage][扫码订单付款完成事件({})]", order.getPayNo());
        tryUploadWxMaOrderShippingInfo(order.getPayNo());
    }

    @EventListener
    @Async // Spring Event 默认在 Producer 发送的线程，通过 @Async 实现异步
    public void onMessage(VipOrderPaidMessage message) {
        VipOrderVO order = message.getOrder();
        log.info("[pay/wechat][onMessage][购买会员付款完成事件({})]", order.getPayNo());
        tryUploadWxMaOrderShippingInfo(order.getPayNo());
    }

    @EventListener
    @Async // Spring Event 默认在 Producer 发送的线程，通过 @Async 实现异步
    public void onMessage(AgencyOrderPaidMessage message) {
        AgencyOrderVO order = message.getOrder();
        log.info("[pay/wechat][onMessage][招商人员入驻缴费完成事件({})]", order.getPayNo());
        tryUploadWxMaOrderShippingInfo(order.getPayNo());
    }

    @EventListener
    @Async // Spring Event 默认在 Producer 发送的线程，通过 @Async 实现异步
    public void onMessage(CloudAllianceOrderPaidMessage message) {
        CloudAllianceOrderVO order = message.getOrder();
        log.info("[pay/wechat][onMessage][云盟商入驻缴费完成事件({})]", order.getPayNo());
        tryUploadWxMaOrderShippingInfo(order.getPayNo());
    }

    @EventListener
    @Async // Spring Event 默认在 Producer 发送的线程，通过 @Async 实现异步
    public void onMessage(WalletRechargerPaidMessage message) {
        log.info("[pay/wechat][onMessage][钱包充值成功事件({})]", message.getPayNo());
        tryUploadWxMaOrderShippingInfo(message.getPayNo());
    }

    @EventListener
    @Async // Spring Event 默认在 Producer 发送的线程，通过 @Async 实现异步
    public void onMessage(WechatOrderShippingMessage message) {
        log.info("[pay/wechat][onMessage][微信订单发货事件({})]", message.getPayNo());
        tryUploadWxMaOrderShippingInfo(message.getPayNo());
    }

    @EventListener
    @Async // Spring Event 默认在 Producer 发送的线程，通过 @Async 实现异步
    public void onMessage(WechatOrderInfoSyncMessage message) {
        log.info("[pay/wechat][onMessage][微信订单分账事件({})]", message.getPayNo());
        trySyncWxMaOrderInfo(message.getPayNo());
    }

    private void tryUploadWxMaOrderShippingInfo(TradeOrderRespDTO order) {
        try {
            WxaUploadOrderShippingInfoDTO dto = buildWxaUploadOrderShippingInfoDTO(order.getPayNo());
            if (dto == null) {
                return;
            }
            dto.setReceiverContact(order.getReceiverMobile());
            if (DeliveryTypeEnum.EXPRESS.getType().equals(order.getDeliveryType()) && StrUtil.isNotEmpty(order.getLogisticsNo())) {
                dto.setLogisticsType(WxaUploadOrderShippingInfoDTO.LOGISTICS_TYPE_EXPRESS);
                dto.setLogisticsNo(order.getLogisticsNo());
            } else if (DeliveryTypeEnum.PICK_UP.getType().equals(order.getDeliveryType())) {
                dto.setLogisticsType(WxaUploadOrderShippingInfoDTO.LOGISTICS_TYPE_PICK_UP);
            } else {
                dto.setLogisticsType(WxaUploadOrderShippingInfoDTO.LOGISTICS_TYPE_VIRTUAL);
            }
            SpringUtil.getBean(WechatClientApi.class).uploadWxMaOrderShippingInfo(UserTypeEnum.MEMBER.getValue(), dto);
        } catch (Exception ex) {
            log.error("[pay/wechat][tryUploadWxMaOrderShippingInfo][订单({})上传订单物流信息到微信小程序失败]", order.getPayNo(), ex);
        }
    }

    private void tryUploadWxMaOrderShippingInfo(String payNo) {
        try {
            WxaUploadOrderShippingInfoDTO dto = buildWxaUploadOrderShippingInfoDTO(payNo);
            if (dto == null) {
                return;
            }
            dto.setLogisticsType(WxaUploadOrderShippingInfoDTO.LOGISTICS_TYPE_VIRTUAL);
            // 付款成功后延时一下，给微信一点处理时间，否则调用微信的发货接口会提示订单不存在
            ThreadUtil.safeSleep(15 * 1000);
            SpringUtil.getBean(WechatClientApi.class).uploadWxMaOrderShippingInfo(UserTypeEnum.MEMBER.getValue(), dto);
        } catch (Exception ex) {
            log.error("[pay/wechat][tryUploadWxMaOrderShippingInfo][订单({})上传订单物流信息到微信小程序失败]", payNo, ex);
        }
    }

    private WxaUploadOrderShippingInfoDTO buildWxaUploadOrderShippingInfoDTO(String payNo) {
        PayOrderVO orderVO = SpringUtil.getBean(PayOrderApi.class).getOrderByNo(payNo);
        if (!UnifiedPayChannelEnum.isWxLite(orderVO.getChannelCode())) {
            // 注意：只有微信小程序支付的订单，才需要同步物流信息
            log.debug("[pay/wechat][buildWxaUploadOrderShippingInfoDTO][订单({}/{})非微信小程序支付，不上传订单物流信息到微信小程序]", orderVO.getTradeNo(), payNo);
            return null;
        }
        // MallBook 聚合微信支付的渠道单号并不是微信的支付单号，需特殊处理
        String transactionId = parseTransactionId(orderVO.getChannelNotifyData());
        if (StrUtil.isBlank(transactionId)) {
            transactionId = orderVO.getChannelOrderNo();
        }
        WxaUploadOrderShippingInfoDTO dto = new WxaUploadOrderShippingInfoDTO();
        dto.setTransactionId(transactionId);
        dto.setOpenid(orderVO.getChannelUserId());
        dto.setItemDesc(orderVO.getSubject());
        return dto;
    }

    private void tryNotifyWxMaOrderConfirmReceive(TradeOrderRespDTO order) {
        try {
            PayOrderVO orderVO = SpringUtil.getBean(PayOrderApi.class).getOrderByNo(order.getPayNo());
            if (!UnifiedPayChannelEnum.isWxLite(orderVO.getChannelCode())) {
                // 注意：只有微信小程序支付的订单，才通知用户到微信小程序确认收货
                log.debug("[pay/wechat][tryNotifyWxMaOrderConfirmReceive][订单({}/{})非微信小程序支付，不通知用户到微信小程序确认收货]", orderVO.getTradeNo(), order.getPayNo());
                return;
            }
            // MallBook 聚合微信支付的渠道单号并不是微信的支付单号，需特殊处理
            String transactionId = parseTransactionId(orderVO.getChannelNotifyData());
            if (StrUtil.isBlank(transactionId)) {
                transactionId = orderVO.getChannelOrderNo();
            }
            WxaOrderNotifyConfirmReceiveDTO dto = new WxaOrderNotifyConfirmReceiveDTO();
            dto.setTransactionId(transactionId);
            dto.setReceivedTime(order.getReceiveTime());
            SpringUtil.getBean(WechatClientApi.class).notifyWxMaOrderConfirmReceive(UserTypeEnum.MEMBER.getValue(), dto);
        } catch (Exception ex) {
            log.error("[pay/wechat][tryNotifyWxMaOrderConfirmReceive][订单({})通知用户到微信小程序确认收货失败]", order.getPayNo(), ex);
        }
    }

    private void trySyncWxMaOrderInfo(String payNo) {
        try {
            PayOrderVO orderVO = SpringUtil.getBean(PayOrderApi.class).getOrderByNo(payNo);
            if (!UnifiedPayChannelEnum.isWxLite(orderVO.getChannelCode())) {
                // 注意：只有微信小程序支付的订单，才同步微信订单信息
                log.debug("[pay/wechat][trySyncWxMaOrderInfo][订单({}/{})非微信小程序支付，不同步微信订单信息]", orderVO.getTradeNo(), payNo);
                return;
            }
            // MallBook 聚合微信支付的渠道单号并不是微信的支付单号，需特殊处理
            String transactionId = parseTransactionId(orderVO.getChannelNotifyData());
            if (StrUtil.isBlank(transactionId)) {
                log.warn("[pay/wechat][trySyncWxMaOrderInfo][订单({})从回调数据中未获取到对应的微信单号，不同步微信订单信息]", payNo);
                return;
            }
            WechatOrderDetailVO result = SpringUtil.getBean(WechatClientApi.class).getWxMaOrderInfo(UserTypeEnum.MEMBER.getValue(), transactionId);
            SpringUtil.getBean(WechatOrderInfoMapper.class).saveResult(payNo, result);
        } catch (Exception ex) {
            log.error("[pay/wechat][trySyncWxMaOrderInfo][订单({})同步微信订单信息出错]", payNo, ex);
        }
    }

    private String parseTransactionId(String channelNotifyData) {
        try {
            //{
            //    "code": "0000",
            //    "msg": "操作成功",
            //    "data": {
            //        "merOrderId": "UPY202507141214099919",
            //        "amount": "990",
            //        "status": "1",
            //        "statusMsg": null,
            //        "payCode": null,
            //        "splitList": null,
            //        "channelOrderId": "ZF1944611348584341505",
            //        "partyOrderId": "022325071444049453146611",
            //        "outTransId": "4200002662202507148134177894",
            //        "parameter1": null,
            //        "parameter2": null,
            //        "toBeSplitAmount": "990"
            //    }
            //}
            return JSONUtil.parseObj(channelNotifyData).getJSONObject("data").getStr("outTransId");
        } catch (Exception e) {
            log.warn("[pay/wechat][parseTransactionId]从 channelNotifyData 中解析微信支付单号失败", e);
            return null;
        }
    }

}
